import numpy as np


def trapezoidal(f, start, end, n):
    interval = (end - start) / n
    s = 0
    for i in range(n):
        s += (f(start + i * interval) + f(start + (i + 1) * interval)) * interval / 2
    return s


def simpson(f, start, end, n):
    interval = (end - start) / n
    s = 0
    for i in range(n):
        s += (f(start + i * interval) + 4 * f(start + (i + 1 / 2) * interval) + f(
            start + (i + 1) * interval)) * interval / 6
    return s


def gauss_legendre_2(f, start, end, n):
    interval = (end - start) / n
    s = 0
    for i in range(n):
        s += (f(start + (i + (np.sqrt(3) - 1) / (2 * np.sqrt(3))) * interval) + f(
            start + (i + (np.sqrt(3) + 1) / (2 * np.sqrt(3))) * interval)) * interval / 2
    return s


def f0(x):
    return x / (4 + x ** 2)


print(trapezoidal(f0, 0, 1, 2))
print(simpson(f0, 0, 1, 2))


def f1(x):
    return np.sqrt(x)


print(trapezoidal(f1, 1, 3, 4))
print(simpson(f1, 1, 3, 4))


def f2(x):
    return 1 / x


print(simpson(f2, 1, 3, 2))
print(gauss_legendre_2(f2, 1, 3, 2))
